#!/usr/bin/env python
# -*- coding: UTF-8 -*-

from OpenGL.GL import *
from OpenGL.GLUT import	*
from OpenGL.GLU	import *

from glew import *
import socket

from texturegl import *

from math import *

import sys
import time
import threading

import pOSC

def	launchConsole(loc=globals()):
	from threading import Thread
	from code import interact
	Thread(target=interact,args=(None,None,loc)).start()

class var:

	def __init__(self,b):
		self.true = b
		
	def toggle(self):
		if self.true == False:
			self.true = True
		else:
			self.true = False


class Scene:
	def	__init__(self, width=640, height=480, fullscreen = False):
		self.title = "vj krute"
		self.fullscreen = fullscreen
		
		self.width = width
		self.height = height
		
		self.ESCAPE	= '\033'
		self.window	= 0

		self.t0	= 0.0
		self.t1 = 0.0
		self.dt = 0

		self.rtri =	0.5
		self.triRate = 3.0
				
		self.autopilot = False 
		self.timer = None
		self.interval = 30
		
		self.nrColumns = 1
		self.nrRow = 1
		self.currentColumn = 0
		self.currentRow = 0
		
		self.pause = var(False)
		self.FOV = 90
		
		self.osc = pOSC.OSCReciever(self.OSCParser)
		
		self.tbuffer = Billboard(1024)
		
		self.color = [0,0,1]
		
		self.lightPos =[
			[ -.5, 0.0,	0.0, 0.0],
			[ 0.0, -.5,	0.0, 0.0],
			[ 0.0, 0.0,	0.5, 0.0],
			[ 0.0, 0.0,	0.0, 0.0]
		]
		
		self.lightSpec=[
			[ 0.9,	0.0,  0.4, 1.0],
			[ 0.4,	0.7,  0.0, 1.0],
			[ 0.0,	0.7,  0.4, 1.0],
			[ 0.4,	0.0,  0.9, 1.0]
		]
		
		self.lightDiff=[
			[ 0.0,	0.4,  0.6, 1.0],
			[ 0.0,	0.6,  0.4, 1.0],
			[ 0.4,	0.6,  0.0, 1.0],
			[ 0.6,	0.4,  0.0, 1.0]
		]
		
		self.lightAmb=[0.07, 0.07, 0.07, 1.0]
		
		
	def perspective(self,  fovy, aspect, zNear, zFar ):
		ymax = zNear * math.tan(fovy * math.pi / 360.0)
		ymin = -ymax
		xmin = ymin * aspect
		xmax = ymax * aspect
		self.frustum(xmin, xmax, ymin, ymax, zNear, zFar)
	
	def tile(self, x, y, maxX, maxY):
		self.nrColumns = maxX
		self.nrRows = maxY
		
		if x >= self.nrColumns:
			self.currentColumn = 0
		else:
			self.currentColumn = x
			
		if y >= self.nrRows:
			self.currentRow = 0
		else:
			self.currentRow = y
			
	
	def frustum(self, xmin, xmax, ymin, ymax, zNear, zFar):
	
		border = 0
		
		imageWidth = self.width*self.nrColumns
		imageHeight = self.height*self.nrRows
	
		left = xmin + (xmax - xmin) * (self.currentColumn * self.width) / imageWidth
		right = left + (xmax - xmin) * self.width / imageWidth
		bottom = ymin + (ymax - ymin)  * (self.currentRow * self.height) / imageHeight
		top = bottom + (ymax - ymin) * self.height / imageHeight
		
   		glFrustum(left, right, bottom, top, zNear, zFar)
   		
   	def save(self, filename):
   	
   		import os
		glPixelStorei(GL_PACK_ALIGNMENT, 1)		data = glReadPixelsub(0, 0, self.width, self.height, GL_RGB)
		assert data.shape == (self.width,self.height,3), """Got back array of shape %r, expected %r"""%(data.shape,(self.width,self.height,3),)
		image = Image.fromstring( "RGB", (self.width, self.height), data.tostring() )		image = image.transpose( Image.FLIP_TOP_BOTTOM)		image.save( filename)		print 'Saved image to %s'% (os.path.abspath( filename))
   		
   	def OSCParser(self, message):
   		print(message)

	def	initLighting(self):
		# from peters lightsetup
		glShadeModel(GL_SMOOTH)

		for	i in range(4):
			glLightfv(GL_LIGHT0+i, GL_POSITION,	self.lightPos[i])
			glLightfv(GL_LIGHT0+i, GL_DIFFUSE, self.lightDiff[i])
			glLightfv(GL_LIGHT0+i, GL_SPECULAR,	self.lightSpec[i])
			glLightfv(GL_LIGHT0+i, GL_AMBIENT, self.lightAmb)
			glEnable(GL_LIGHT0+i)

		glEnable(GL_LIGHTING)


	def regenerate(self):
			
		if self.autopilot == True:
			print("Timer interval is ", self.interval, "seconds")
			self.timer = threading.Timer(self.interval, self.regenerate)
			self.timer.start()

	def	init(self):
		self.osc.start()
		self.tile(0,0,1,1)
		
		err = glewInit()
		if(err == GLEW_OK):
			print("glew iniatilized properly.")
		else:
			print("glew failed!")
			
		self.t0=time.clock()
		
		glClearColor(1.,1.,1.,1.0)	# clear	background color to this
		glClearDepth(1.0)					# enables clearing of depth	buffer
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
		glDepthFunc(GL_LESS)				# type of depth	test to	do
		glEnable(GL_DEPTH_TEST)				# enables depth	testing
		glShadeModel(GL_SMOOTH)				# enables smooth color shading

	def	resize(self, width,	height):
		self.width = width
		self.height = height
		if height == 0:	return
		glViewport(0, 0, width,	height)
		glMatrixMode(GL_PROJECTION)
		glLoadIdentity()
		self.perspective(self.FOV, float(width)/float(height), 0.1, 100)
		glMatrixMode(GL_MODELVIEW)
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

	def	getcoord(self,x,y,z):
		viewport = []
		modelview =	[]
		projection = []
		
		viewport = glGetIntegerv(GL_VIEWPORT)
		#viewport = [0,0,640,480]
		modelview = glGetDoublev(GL_MODELVIEW_MATRIX)
		projection = glGetDoublev(GL_PROJECTION_MATRIX)
		
		nx = ny	= nz = 0
		nx,ny,nz = gluUnProject(x, y, z, modelview, projection, viewport);
		
		return vector([nx,ny,nz])
		

	def	display(self):
		# render stuff here
	
#		glBindTexture(GL_TEXTURE_2D, self.tbuffer)

#		glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 0, 0, 1024, 1024, 0)
	
		# clear	screen and depth buffer
		self.color = [0,0,0]
		glClearColor(self.color[0],self.color[1],self.color[2],1)
		glClear(GL_COLOR_BUFFER_BIT	| GL_DEPTH_BUFFER_BIT)
		glClear(GL_DEPTH_BUFFER_BIT)
		
#		glViewport(0 , 0, self.width, self.height)
		
		glMatrixMode(GL_PROJECTION)
		glLoadIdentity()                # reset the     projection matrix
		self.perspective(self.FOV, float(self.width)/float(self.height), 0.1, 100)
                                                # calculate     aspect ratio of window
		glMatrixMode(GL_MODELVIEW)
		glLoadIdentity()		   # reset view


	def	idle(self):
		if self.pause.true:
			self.triRate = 0
		else:
			self.triRate = 3.0
			
	#	self.color[0] = self.monome.getValue()

		self.t1=time.clock()
		self.dt=self.t1-self.t0
		if self.dt>0:
			self.t0=self.t1
			self.rtri += self.triRate*self.dt
			glutPostRedisplay()


	def	keyboard(self, key,	x, y):
		if key == self.ESCAPE:
			self.osc.stop()
			sys.exit()

	#	this shit is dangerous on os x
	#	if key == 'a':
	#		print("Autopilot is ON!")
	#		self.autopilot = True
	#		self.regenerate()
		if key == 'm':
			print("Autopilot is OFF!")
			self.autopilot = False
			self.timer.cancel()
		
		if key == 'F':
			self.windowprops = (
				glutGet(GLUT_WINDOW_X),
				glutGet(GLUT_WINDOW_Y),
				glutGet(GLUT_WINDOW_WIDTH),
				glutGet(GLUT_WINDOW_HEIGHT),
			)
			glutFullScreen()
			
		if key == 'f':
			posx,posy,sizex,sizey = self.windowprops
			glutReshapeWindow(sizex,sizey)
			glutPositionWindow(posx,posy)
			
		
		if key == 'V':
			self.FOV += 1
		if key == 'v':
			self.FOV -= 1	
			
		if key == 'p':
			self.pause.toggle()
			
		if key == 'q':
			self.monome = None

	def	mouse(self,	button,	state, x, y):
		return

	def	main(self, argv):
		glutInit(argv)
		glutInitDisplayMode(GLUT_RGBA |	GLUT_DOUBLE	| GLUT_DEPTH)
		glutInitWindowSize(self.width,	self.height)
		self.window	= glutCreateWindow(self.title)
		if self.fullscreen:
			glutFullScreen()

		glutDisplayFunc(self.display)
		glutIdleFunc(self.idle)
		glutReshapeFunc(self.resize)
		glutKeyboardFunc(self.keyboard)
		glutMouseFunc(self.mouse)

		self.init()
		glutMainLoop()
